﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Data.OleDb;

namespace SerialTool
{
    public partial class MainDialog : Form
    {
        /// <summary>
        /// 串口组件
        /// </summary>
        private Comm comm;
        
        /// <summary>
        /// 配置信息
        /// </summary>
        private ConfigClass config;
      
        public int DisplaySendFlag = 0x0;   //显示发送标志，1代表发送，0代表不发送
        public int LineFeedFlag = 0x0;      //自动换行标志，1代表换行，0带便不换行
        public int TimeDisplayFlag = 0x0;   //时间显示标志，1代表现实时间，0代表不显示时间 
        public int HexSendFlag = 0x0;       //十六进制发送标志，1代表十六进制方式发送，0代表ASCII方式发送
        public int HexReceFlag = 0x0;       //十六进制接收标志,1 代表十六进制方式接收， 0代表ASCII方式接收

        BackgroundWorker backgroundWorker;

        //获取所有的串口
        public void SearachSerialPort()
        {
            string[] portlist = System.IO.Ports.SerialPort.GetPortNames();

            CommClose();
            SerialPortNum.Items.Clear();
            SerialPortNum.Text = "";

            for (int i = 0; i < portlist.Length; i++)
            {
                SerialPortNum.Items.Add(portlist[i]);
            }         
        }

        /// <summary>
        /// 异步执行串口任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void DoSerialWork(object sender, DoWorkEventArgs e)
        {
            //Download File 
            switch (config.fileprotocal)
            {
                case FileProtocal.Xmodem:
                    //MessageBox.Show("Xmodem Send File Start");                
                    break;
                case FileProtocal.Ymodem:
                    //MessageBox.Show("Ymodem Send File Start");
                    e.Result = YmodemSendFile();
                    break;
                case FileProtocal.Zmodem:
                    MessageBox.Show("Zmodem Send File Start");
                    break;
                case FileProtocal.Kermit:
                    MessageBox.Show("Kermit Send File Start");
                    break;
                default:
                    break;
            };
        }

        /// <summary>
        /// 异步执行的串口任务进度改变处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="?"></param>
        public void OnSerialProcessChanged(object senddr, ProgressChangedEventArgs e)
        {
            this.DownloadFileProgressBar.Value = e.ProgressPercentage;
        }

        /// <summary>
        /// 异步串口任务执行完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnSerialWorkCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                this.DownloadFileStatus.Text = "下载取消...";
                this.DownloadFileStatus.ForeColor = Color.Red;
                this.DownloadFileProgressBar.Value = 0;                
                return;
            }
            else
            {
                int ret;
                if (e.Result == null)
                {
                    return;
                }
                else
                {
                    ret = int.Parse(e.Result.ToString());               
                    switch (ret)
                    { 
                        case 0:
                            this.DownloadFileStatus.Text = "下载完成..." + e.Result.ToString() + "value " + this.DownloadFileProgressBar.Value.ToString();
                            this.DownloadFileStatus.ForeColor = Color.Green;
                            break;
                        case 1:
                            this.DownloadFileStatus.Text = "用户取消";
                            this.DownloadFileStatus.ForeColor = Color.Red;
                            break;
                        case 10:
                            this.DownloadFileStatus.Text = "链接超时";
                            this.DownloadFileStatus.ForeColor = Color.Red; 
                            break;
                        default:                        
                            break;
                    }
                }
            }

            this.DownloadFileButton.Enabled = true;
            this.CancelDownFileButton.Enabled = false;
        }
     

        /// <summary>
        /// 打开串口
        /// </summary>
        public void CommOpen()
        {
            comm.Open();

            if (comm.IsOpen)
            {
                comm.DataReceived += new Comm.EventHandle(comm_DataReceived);

                SerialButton.Text = "关闭";
                SerialPortNum.Enabled = false;
                SerialBaudrate.Enabled = false;
                SerialDataBits.Enabled = false;
                SerialStopBit.Enabled = false;
                SerialParityBit.Enabled = false;
            }   
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        public void CommClose()
        {
            comm.Close();
            if (!comm.IsOpen)
            {
                comm.DataReceived -= new Comm.EventHandle(comm_DataReceived);

                SerialButton.Text = "打开";
                SerialPortNum.Enabled = true;
                SerialBaudrate.Enabled = true;
                SerialDataBits.Enabled = true;
                SerialStopBit.Enabled = true;
                SerialParityBit.Enabled = true;
            }  
        }

        /// <summary>
        /// 初始化对话框和组件
        /// </summary>
        public MainDialog()
        {            
            InitializeComponent();
            comm = new Comm();
            config = new ConfigClass();
            backgroundWorker = new BackgroundWorker();

            SearachSerialPort();          

            backgroundWorker.DoWork += DoSerialWork;                        //异步实现过程
            backgroundWorker.WorkerSupportsCancellation = true;             //设置支持取消异步方式
            backgroundWorker.WorkerReportsProgress = true;                  //设置支持处理进度值
            backgroundWorker.ProgressChanged += OnSerialProcessChanged;     //处理进度值的改变
            backgroundWorker.RunWorkerCompleted += OnSerialWorkCompleted;   //处理完成任务之后的改变

        }

        /// <summary>
        /// 退出应用程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //释放占用的资源再退出
            comm.serialPort.Close();
      
            
            Application.Exit();
        }

  

        /// <summary>
        /// 串口接收数据事件中调用线程将接收到的数据显示在接收区
        /// </summary>
        /// <param name="readBuffer"></param>
        void comm_DataReceived(byte[] readBuffer)
        {
            //接收到数据的缓冲区
            string ReadString = System.Text.Encoding.Default.GetString(readBuffer);
            string TmpString = "";

            String TimeString = "";

            //显示系统时间
            if (0x01 == TimeDisplayFlag)
            {
                //显示时间秒
                DateTime CurrentTime = System.DateTime.Now;
                
                TimeString = "\n" + CurrentTime.ToShortTimeString() + "\n";
            }

            if (HexReceFlag == 1)
            {
                //十六进制方式显示接收到的数据            
                char[] values = ReadString.ToCharArray();
                

                foreach (char letter in values)
                {
                    if (' ' == letter)
                    {
                        continue;
                    }
                    else
                    {
                        // Get the integral value of the character.
                        int value = Convert.ToInt32(letter);
                        // Convert the decimal value to a hexadecimal value in string form.
                        string hexOutput = String.Format("{0:X}", value);
                        //Console.WriteLine("Hexadecimal value of {0} is {1}", letter, hexOutput);
                        //ReadString += hexOutput + " ";
                        TmpString += hexOutput + " ";
                    }
                }
            }
            else
            { 
                //ASCII方式接收到数据，并显示
                //ASCII的数据不用处理
                TmpString = ReadString;
            }

            //接收到的数据自动换行
            if (0x01 == LineFeedFlag)
            {
                TmpString += "\n";
            }

                //挂载显示数据
                this.SerialDataReceived.Invoke(
                    //在拥有此控件的基础窗口句柄的线程上执行委托Invoke(Delegate)
                    //即在textBox_ReceiveDate控件的父窗口form中执行委托.
                   new MethodInvoker( //表示一个委托，该委托可执行托管代码中声明为 void 且不接
                    //受任何参数的任何方法。在对控件的 Invoke 方法进行调用时
                    //或需要一个简单委托又不想自己定义时可以使用该委托。
                   delegate
                   {
                       //匿名方法,C#2.0的新功能，这是一种允许程序员将一段完整
                       //代码区块当成参数传递的程序代码编写技术，通过此种方法可以直接使用委托来设计事件响应程序
                       //以下就是你要在主线程上实现的功能，但是有一点要注意，这里不适宜处理过多的方法，因为C#消息机
                       //制是消息流水线响应机制，如果这里在主线程上处理语句的时间过长会导致主UI线程阻塞，停止响应或响
                       //应不顺畅,这时你的主form界面会延迟或卡死
                       //输出到主窗口                   
                       this.SerialDataReceived.AppendText(TimeString + TmpString);
                   }
                    ));             
             
        }

        /// <summary>
        /// 打开关闭串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialButton_Click(object sender, EventArgs e)
        {
            if ("打开" == SerialButton.Text)
            {               
                if (SerialPortNum.Text.Length != 0)
                {                  
                    //串口ID
                    comm.serialPort.PortName = SerialPortNum.Text;

                    //波特率
                    if ("1200" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 1200;
                    else if ("1800" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 1800;               
                    else if ("2400" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 2400;
                     else if ("3600" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 3600;
                    else if ("4800" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 4800;
                    else if ("7200" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 7200;
                    else if ("9600" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 9600;
                    else if ("14400" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 14400;
                    else if ("19200" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 19200;
                    else if ("28800" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 28800;
                    else if ("38400" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 38400;
                    else if ("57600" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 57600;
                    else if ("115200" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 115200;
                    else if ("230400" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 230400;
                    else if ("460800" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 460800;
                    else if ("614400" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 614400;
                    else if ("921600" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 921600;
                    else if ("1228800" == SerialBaudrate.Text)
                        comm.serialPort.BaudRate = 1228800;                    
                    else
                        comm.serialPort.BaudRate = 2400;

                    //数据位
                    if ("8" == SerialDataBits.Text)
                        comm.serialPort.DataBits = 8;
                    else if ("9" == SerialDataBits.Text)
                        comm.serialPort.DataBits = 9;
                    else if ("10" == SerialDataBits.Text)
                        comm.serialPort.DataBits = 10;
                    else
                        comm.serialPort.DataBits = 8;

                    //停止位
                    if ("1" == SerialStopBit.Text)
                        comm.serialPort.StopBits = System.IO.Ports.StopBits.One;
                    else if ("1.5" == SerialStopBit.Text)
                        comm.serialPort.StopBits = System.IO.Ports.StopBits.OnePointFive;
                    else if ("2" == SerialStopBit.Text)
                        comm.serialPort.StopBits = System.IO.Ports.StopBits.Two;
                    else
                        comm.serialPort.StopBits = System.IO.Ports.StopBits.One;
                    
                    //奇偶校验位
                    if("无" == SerialParityBit.Text)
                        comm.serialPort.Parity = System.IO.Ports.Parity.None;
                    else if("奇" == SerialParityBit.Text)
                        comm.serialPort.Parity = System.IO.Ports.Parity.Even;
                    else if ("偶" == SerialParityBit.Text)
                        comm.serialPort.Parity = System.IO.Ports.Parity.Odd;
                    else
                        comm.serialPort.Parity = System.IO.Ports.Parity.None;

                    comm.serialPort.ReadTimeout = 100;
                    comm.serialPort.WriteTimeout = -1;

                    CommOpen();
                }
                else
                {
                    MessageBox.Show("请选择串口");
                }
            }
            else if ("关闭" == SerialButton.Text)
            {
                CommClose();       
            }
        }

        private void DownloadFileButton_Click(object sender, EventArgs e)
        {
            if (DownloadFilePath.Text.Length == 0)
            {
                MessageBox.Show("请选择下载文件！");  
            }
            else
            {
                //下载程序按钮处理程序
                if (DownloadFileButton.Text == "烧写程序")
                {                        
                    //Download Process                
                    comm.SendFilePath = config.DownloadFilePath;
                    DownloadFileProgressBar.Value = 0;
                    if (backgroundWorker.IsBusy)
                    {
                        MessageBox.Show("正在下载...");
                    }
                    else
                    {
                        backgroundWorker.RunWorkerAsync();              //运行同步任务开始下载程序

                        this.DownloadFileStatus.ForeColor = Color.Black;
                        this.DownloadFileStatus.Text = "正在下载";
                        this.DownloadFileButton.Enabled = false;
                        this.CancelDownFileButton.Enabled = true;
                    }                                                       
                }
            }       
        }

        /// <summary>
        /// 用定时器刷新显示系统时间
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SystemTimer_Tick(object sender, EventArgs e)
        {
            DateTime CurrentTime = System.DateTime.Now;
            TimeStatusLabel.Text = "当前时间：" + CurrentTime.ToString();
        }

        /// <summary>
        /// 清空数据接收区
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CleanBufferButton_Click(object sender, EventArgs e)
        {
            SerialDataReceived.Text = "";
        }

        /// <summary>
        /// 保存数据接收区的值到文件中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DownloadFileOpenButton_Click(object sender, EventArgs e)
        {
            //打开文件对话框
            String fileName;        //包含整个完整的路径和文件名
            //String folderName;      //目录名
            String extendedName;    //文件扩展名

            OpenFileDialog ofd = new OpenFileDialog();              //new一个方法
            if (config.DownloadFilePath == "")
            {
                ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); //定义打开的默认文件夹位置
            }
            else
            {
                ofd.InitialDirectory = config.DownloadFilePath;
            }

            ofd.Filter = "下载文件(*.bin,*.hex)|*.bin;*.hex";
            ofd.FilterIndex = 0;               //在对话框中选择的文件筛选器的索引，如果选第一项就设为1
            ofd.RestoreDirectory = true;

            //判断是否选择的打开文件
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                fileName = ofd.FileName;                                //获得选择的文件路径
                extendedName = Path.GetExtension(fileName);             //获得文件扩展名

                if (extendedName == ".bin" || extendedName == ".hex")
                {
                    DownloadFilePath.Text = fileName;                           //显示文件路径和文件名
                    DownloadFileVersion.Text = Path.GetFileName(fileName);          //获得文件名                 
                    if (extendedName == ".hex")
                    {
                        //Hex To Bin,将十六进制文件转换为二进制文件
                    }
                 
                    //保存要下载的二进制文件全路径
                    config.DownloadFilePath = fileName; 
                    config.FILE_NAME_LENGTH = DownloadFileVersion.Text.Length;

                    //MessageBox.Show("文件路径 " + DownloadFilePath.Text + "文件" + DownloadFileVersion.Text);
                }
                else
                {
                    MessageBox.Show("请选择hex或bin文件");
                }

            }
        }

        /// <summary>
        /// 窗口置顶
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DiolagTopFlag_CheckedChanged(object sender, EventArgs e)
        {
            if (DiolagTopFlag.Checked == true)
            {
                this.TopMost = true; 
            }
            else
            {
                this.TopMost = false;
            }
        }

        private void 关于ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("本软件只用于学习，不用于商业用途。526892120@qq.com");
        }

        private void SaveBuffButton_Click(object sender, EventArgs e)
        {
            //保存buffer的内容到文件中去
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.InitialDirectory = "E:\\";
            sfd.Filter = "Text文件(*.txt)|*.txt";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                //该编码类型不会改变已有文件的编码类型
                StreamWriter sw = new StreamWriter(sfd.FileName, true, Encoding.Default);
                sw.Write(SerialDataReceived.Text);          
                sw.Close();            
            }
        }

        /// <summary>
        /// 将十六进制的字符串转换成二进制
        /// </summary>
        /// <param name="hexstring"></param>
        /// <returns></returns>
        public static byte[] HexStringToBinary(string hexstring)
        {
            //将字符串数据以' '空格来分割
            string[] tmpary = hexstring.Trim().Split(' ');
            //新建Length长的数组来缓存数据
            byte[] buff = new byte[tmpary.Length];
            for (int i = 0; i < buff.Length; i++)
            {
                try
                {
                    buff[i] = Convert.ToByte(tmpary[i], 16);//转换
                }
                catch (System.ArgumentException)
                {
                    continue;
                }
                catch (System.OverflowException)
                {
                    continue;
                }
                catch (System.FormatException)
                {
                    continue;

                }
            }
            return buff;
        }

        /// <summary>
        /// 按下按钮，串口按照发送方式来发送发送缓冲区的数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void SerialSendButton_Click(object sender, EventArgs e)
        {
            //串口发送数据，根据读取到的数据和定时器来发送数据
            bool OpenFlag = comm.serialPort.IsOpen;
            if (true == OpenFlag)
            {
                //按下发送按钮，获取发送缓冲区的数据
                string SerialSendTemp = SerialDataSend.Text;

                if (0x00 == HexSendFlag)
                {
                    //ASCII方式发送
                    comm.serialPort.Write(SerialSendTemp);              
                }
                else
                {
                    //Hex方式发送
                    Byte[] SendData = HexStringToBinary(SerialSendTemp);
                    comm.serialPort.Write(SendData, 0, SendData.Length);
                }

                //在接收区显示发送的数据
                if (0x1 == DisplaySendFlag)
                {                    
                    SerialDataReceived.Text += SerialSendTemp;
                    SerialDataReceived.Text += "\n";
                }

                if (0x01 == LineFeedFlag)
                {
                    SerialDataReceived.Text += "\n";
                }             
            }
            else
            {
                MessageBox.Show(" 串口没打开！");
            }
        }

        /// <summary>
        /// 定时发送周期改变时，重新加载周期值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendTimerPeriod_TextChanged(object sender, EventArgs e)
        {
            int period = 0;
            //如果文本框中的内容改变的话，就根据改变的内容修改定时发送周期的值
            try
            {
                string StringPeriod = SendTimerPeriod.Text;

                if ("" == StringPeriod)
                {
                    return;
                }

                period = Convert.ToInt16(StringPeriod);
                //转换为16进制数
            }
            catch (System.ArgumentException)
            {
                MessageBox.Show("输入的数据不对！");
                return;
            }
            catch (System.FormatException)
            {
                MessageBox.Show("输入的数据格式不对！");
                return;
            }
            catch (System.OverflowException)
            {
                MessageBox.Show("输入的数据太大，请输入小数！");
                return;
            }

            SendTimer.Enabled = false;
            SendTimer.Interval = period;   //以ms为单位
            SendTimer.Enabled = true;
        }

        private void SendCheckHex_CheckedChanged(object sender, EventArgs e)
        {
            //发送方式选择
            if (SendCheckHex.Checked == true)
            {
                HexSendFlag = 0x01;
            }
            else
            {
                HexSendFlag = 0x00;
            }

        }

        private void SendCheckASCII_CheckedChanged(object sender, EventArgs e)
        {
            //发送方式选择
            if (SendCheckASCII.Checked == true)
            {
                HexSendFlag = 0x00;
            }
            else
            {
                HexSendFlag = 0x01;
            }
        }

        private void ReceiveCheckASCII_CheckedChanged(object sender, EventArgs e)
        {
            //接收方式选择ASCII
            if (ReceiveCheckASCII.Checked == true)
            {
                HexReceFlag = 0x00;
            }
            else
            {
                HexReceFlag = 0x01;
            }
        }

        private void ReceiveCheckHex_CheckedChanged(object sender, EventArgs e)
        {
            //接收方式选择Hex
            if (ReceiveCheckHex.Checked == true)
            {
                HexReceFlag = 0x01;
            }
            else
            {
                HexReceFlag = 0x00;
            }
        }

        /// <summary>
        /// 设置接收到数据是否自动换行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AutoLineBackFlag_CheckedChanged(object sender, EventArgs e)
        {
            //自动换行
            if (true == AutoLineBackFlag.Checked)
            {
                LineFeedFlag = 0x01;
            }
            else
            {
                LineFeedFlag = 0x0;
            }
        }

        /// <summary>
        /// 在接收区显示发送的数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DisSendCheck_CheckedChanged(object sender, EventArgs e)
        {
            if (DisSendCheck.Checked == true)
            {
                DisplaySendFlag = 1;
            }
            else
            {
                DisplaySendFlag = 0;
            }
        }

        /// <summary>
        /// 在接收区显示接收到数据的时间
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DisTimeCheck_CheckedChanged(object sender, EventArgs e)
        {
            if (DisTimeCheck.Checked == true)
            {
                TimeDisplayFlag = 1;
            }
            else
            { 
                TimeDisplayFlag = 0;
            }
        }

        /// <summary>
        /// 开启或关闭定时发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TimeSendCheck_CheckedChanged(object sender, EventArgs e)
        {
            if (TimeSendCheck.Checked == true)
            {
                SendTimer.Start();
            }
            else
            {
                SendTimer.Stop();
            }
        }

        /// <summary>
        /// 定时器定时发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendTimer_Tick(object sender, EventArgs e)
        {
            if (0 != SerialDataSend.Text.Length)
            {               
                SerialSendButton_Click(sender, e);                
            }
        }

        private void 重新搜索串口ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (comm.IsOpen)
            {
                comm.Close();
            }

            SearachSerialPort();
        }

        private void MainTabPage_Selected(object sender, TabControlEventArgs e)
        {
            //TabPage发生了改变
            switch (MainTabPage.SelectedIndex)
            {
                case 0:
                    {
                        //MessageBox.Show("选中了第一个TabPage.串口数据");
                        comm.StartReading();
                    }
                    break;
                case 1:
                    {
                        //MessageBox.Show("选中了第二个TabPage.基本控制");
                        comm.StopReading();
                    }
                    break;
                case 2:
                    {
                        //MessageBox.Show("选中了第三个TabPage.在线升级");
                        comm.StopReading();                       
                    }
                    break;
                case 3:
                    {
                        //MessageBox.Show("选中了第四个TabPage.图片接收处理");
                        comm.StopReading();                       
                    }
                    break;
                default:
                    break;
            }

        }

        /// <summary>
        /// 取消下载文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CancelDownFileButton_Click(object sender, EventArgs e)
        {
            backgroundWorker.CancelAsync();
        }



        /// <summary>
        /// 用Ymodem协议传输文件，读取返回值
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        uint Ymodem_CheckResponse(byte c)
        {
            return 0;
        }

        /// <summary>
        /// 准备Ymodem第一个数据包,将文件名和文件长度信息计算放在包data中
        /// </summary>
        /// <param name="data"></param>
        /// <param name="fileName"></param>
        /// <param name="length"></param>         
        private void Ymodem_PrepareIntialPacket(byte[] data, byte[] fileName, long length)
        {
            uint i, j;                        //计数
            char[] file_ptr = new char[50];     //文件大小

            /* Make first three packet */
            data[0] = (byte)YmodemCmd.SOH;
            data[1] = 0x00;
            data[2] = 0xff;

            /* 文件名 */
            for (i = 0; i < config.FILE_NAME_LENGTH; i++)
            {
                data[i + (byte)YmodemCmd.PACKET_HEADER] = fileName[i];
            }

            data[i + (byte)YmodemCmd.PACKET_HEADER] = 0x00;

            //将文件大小length转为byte[]存储起来发送
            string TmpString = length.ToString();
            file_ptr = TmpString.ToCharArray();

            //文件大小
            for (j = 0, i = i + (uint)YmodemCmd.PACKET_HEADER + 1; j < file_ptr.Length; )
            {
                data[i++] = (byte)file_ptr[j++];
            }
            data[i++] = (byte)' ';

            for (j = i; j < (uint)YmodemCmd.PACKET_SIZE + (uint)YmodemCmd.PACKET_HEADER; j++)
            {
                data[j] = 0;
            }
        }

        /// <summary>
        /// 准备Ymodem数据包
        /// </summary>
        /// <param name="SourceBuf"></param>
        /// <param name="data"></param>
        /// <param name="pktNo"></param>
        /// <param name="sizeBlk"></param>
        void Ymodem_PreparePacket(byte[] SourceBuf, byte[] data, byte pktNo, uint sizeBlk)
        {
            uint i, size, packetSize;
            byte[] file_ptr;

            /* Make first three packet */
            packetSize = sizeBlk >= (uint)YmodemCmd.PACKET_1K_SIZE ? (uint)YmodemCmd.PACKET_1K_SIZE : (uint)YmodemCmd.PACKET_SIZE;
            size = sizeBlk < packetSize ? sizeBlk : packetSize;

            if (packetSize == (uint)YmodemCmd.PACKET_1K_SIZE)
            {
                data[0] = (byte)YmodemCmd.STX;
            }
            else
            {
                data[0] = (byte)YmodemCmd.SOH;
            }
            data[1] = pktNo;
            data[2] = (byte)(~pktNo);
            file_ptr = SourceBuf;

            /* Filename packet has valid data */
            /* 填充size大小的数据包 */
            for (i = (uint)YmodemCmd.PACKET_HEADER; i < size + (uint)YmodemCmd.PACKET_HEADER; i++)
            {
                data[i] = file_ptr[i];
            }

            //不够一个数据包，数据用EOF来填充
            if (size <= packetSize)
            {
                for (i = size + (uint)YmodemCmd.PACKET_HEADER; i < packetSize + (uint)YmodemCmd.PACKET_HEADER; i++)
                {
                    data[i] = 0x1A; /* EOF (0x1A) or 0x00 */
                }
            }
        }

        /// <summary>
        /// Update CRC16 for input byte
        /// </summary>
        /// <param name="crcIn"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        ushort UpdateCRC16(ushort crcIn, byte b)
        {
            uint crc = crcIn;
            uint i = (uint)b | 0x100;
            do
            {
                crc <<= 1;
                i <<= 1;
                if (0 != (i & 0x100))
                    ++crc;
                if (0 != (crc & 0x10000))
                    crc ^= 0x1021;
            }
            while (0 == (i & 0x10000));

            return ((ushort)crc);
        }


        /// <summary>
        /// Cal CRC16 for YModem Packet
        /// </summary>
        /// <param name="data"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        ushort Cal_CRC16(byte[] data, uint offset, uint size)
        {
            ushort crc = 0;
            uint i;
            for (i = 0; i < size; i++)
            {
                crc = UpdateCRC16(crc, data[i + offset]);
            }
            crc = UpdateCRC16(crc, 0);
            crc = UpdateCRC16(crc, 0);

            return (ushort)crc;
        }

        /// <summary>
        /// 计算YModem Packet累加和
        /// </summary>
        /// <param name="data"></param>
        /// <param name="size"></param>
        /// <returns></returns>       
        byte CalChecksum(byte[] data, uint offset, uint size)
        {
            byte sum = 0;
            for (uint i = 0; i < size; i++)
            {
                sum += data[i + offset];
            }
            return sum;
        }

        /**
          * @brief  Transmit a data packet using the ymodem protocol
          * @param  data
          * @param  length
           * @retval None
          */
        private void Ymodem_SendPacket(byte[] data, ushort length)
        {
            ushort i = 0;
            while (i < length)
            {
                comm.Send_Byte(data[i]);
                i++;
            }
        }


        /// <summary>
        /// 使用Ymodem协议传输文件
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="sendFileName">传输文件名</param>
        /// <param name="sizeFile">传输文件大小</param>
        /// <returns></returns>
        byte YmodemSendFile()
        {
            string SendFilePath = this.config.DownloadFilePath;
            FileInfo finfo = new FileInfo(SendFilePath);
            //文件名
            byte[] SendFileName = Encoding.UTF8.GetBytes(finfo.Name);
            //文件大小
            int sizeFile = (int)finfo.Length;
            //总共下载了的文件大小
            int TotalSendSize = 0;

            //发送数据缓冲区
            byte[] packet_data = new byte[(uint)YmodemCmd.PACKET_1K_SIZE + (uint)YmodemCmd.PACKET_OVERHEAD];
            //文件名数组
            byte[] FileName = new byte[config.FILE_NAME_LENGTH + 1];

            //读取文件数据的缓冲区
            byte[] buf_ptr = new byte[(uint)YmodemCmd.PACKET_1K_SIZE + (uint)YmodemCmd.PACKET_OVERHEAD];
            byte tempCheckSum;               //累加和
            ushort tempCRC;                   //CRC校验和
            byte blkNumber;                   //要发送数据包的块号
            byte[] receivedC = new byte[2];   //接收C返回值
            uint CRC16_F = 1;                 //1,CRC校验发送;0,累加和校验发送
            uint i;
            int errors, ackReceived, size = 0, pktSize;

            FileStream fs = new FileStream(SendFilePath, FileMode.Open);
            BinaryReader br = new BinaryReader(fs, Encoding.Default);
            byte[] file_buffer = new byte[sizeFile];        //读取文件的缓冲区
            br.Read(file_buffer, 0, sizeFile);              //将文件内容读取到缓冲区保存
            long file_offset = 0;

            errors = 0;
            ackReceived = 0;
            for (i = 0; i < config.FILE_NAME_LENGTH; i++)
            {
                FileName[i] = SendFileName[i];
            }

            do
            {
                /* Wait for Ack and 'C' */
                if ((comm.Receive_Byte(receivedC, 1000) == 0) && (receivedC[0] == (byte)YmodemCmd.CRC16))
                {
                    //丢弃串口读取到的数据
                    comm.ClearReadBuffer();
                    ackReceived = 1;
                }

                //取消下载
                if (backgroundWorker.CancellationPending)
                {
                    fs.Close();
                    br.Close();
                    return 1;
                }


            }while((ackReceived == 0) && (errors<0x0A));

            if (errors >= 0x0A)
            {
                return (byte)errors;
            }

            errors = 0;
            ackReceived = 1;

            /* 准备发送第一个包，包含文件名和文件大小*/
            Ymodem_PrepareIntialPacket(packet_data, FileName, sizeFile);
            /* 发送第一个数据包*/
            do
            {
                /* Send Packet */
                Ymodem_SendPacket(packet_data, (ushort)YmodemCmd.PACKET_SIZE + (ushort)YmodemCmd.PACKET_HEADER);
                /* Send CRC or Check Sum based on CRC16_F */
                if (CRC16_F != 0)
                {
                    tempCRC = Cal_CRC16(packet_data, (uint)3, (uint)YmodemCmd.PACKET_SIZE);
                    comm.Send_Byte((byte)(tempCRC >> 8));
                    comm.Send_Byte((byte)(tempCRC & 0xFF));
                }
                else
                {
                    tempCheckSum = CalChecksum(packet_data, 3, (uint)YmodemCmd.PACKET_SIZE);
                    comm.Send_Byte(tempCheckSum);
                }

                /* Wait for Ack and 'C' */
                if ((comm.Receive_Byte(receivedC, 1000) == 0) && (receivedC[0] == (byte)YmodemCmd.ACK))
                {
                    if ((comm.Receive_Byte(receivedC, 1000) == 0) && (receivedC[0] == (byte)YmodemCmd.CRC16))
                    {
                        /* Packet transfered correctly */
                        ackReceived = 1;
                    }
                    else
                    {
                        errors++;
                    }
                }
                else
                {
                    errors++;
                }

                //取消下载
                if (backgroundWorker.CancellationPending)
                {
                    fs.Close();
                    br.Close();
                    return 1;
                }
             
            } while ((0 == ackReceived) && (errors < 0x0A));

            /*第一帧数据包从发了10次，没有接收到校验，说明通信失败*/
            if (errors >= 0x0A)
            {
                fs.Close();
                br.Close();
                return (byte)errors;
            }          


            size = sizeFile;      //要发送的文件大小
            blkNumber = 0x01;     //要发送的包号

            /* Here 1024 bytes package is used to send the packets */
            /* Resend packet if NAK  for a count of 10 else end of commuincation */
            while (0 != size)
            {
                /* Make first three packet */
                int packetSize;
                if (size > (uint)YmodemCmd.PACKET_1K_SIZE)
                {
                    packetSize = (int)YmodemCmd.PACKET_1K_SIZE;
                }
                else if (size > (int)YmodemCmd.PACKET_SIZE)
                {
                    packetSize = (int)YmodemCmd.PACKET_SIZE;
                }
                else
                {
                    packetSize = size;
                }

                //加载头信息
                if (packetSize == (uint)YmodemCmd.PACKET_1K_SIZE)
                {
                    packet_data[0] = (byte)YmodemCmd.STX;
                }
                else
                {
                    packet_data[0] = (byte)YmodemCmd.SOH;
                }
                packet_data[1] = blkNumber;
                packet_data[2] = (byte)(~blkNumber);

                /* 填充size大小的数据包 */
                for (int t = 0; t < packetSize; t++)
                {
                    packet_data[3 + t] = file_buffer[t + file_offset];
                }

                //不够一个数据包，数据用EOF来填充
                if (packetSize < (uint)YmodemCmd.PACKET_SIZE)
                {
                    for (long j = packetSize + (long)YmodemCmd.PACKET_HEADER; j < packetSize + (uint)YmodemCmd.PACKET_HEADER; j++)
                    {
                        packet_data[j] = 0x1A; /* EOF (0x1A) or 0x00 */
                    }
                }

                ackReceived = 0;
                receivedC[0] = 0;
                errors = 0;

                do
                {
                    /* Send next packet */
                    /* 如果要发的包的大小大于1K，就用1K来发包，如果小于1K就用128byte来发包 */
                    if (size >= (int)YmodemCmd.PACKET_1K_SIZE)
                    {
                        pktSize = (int)YmodemCmd.PACKET_1K_SIZE;
                    }
                    else
                    {
                        pktSize = (int)YmodemCmd.PACKET_SIZE;
                    }

                    //发送包和校验值              
                    Ymodem_SendPacket(packet_data, (ushort)(pktSize + (ushort)YmodemCmd.PACKET_HEADER));
                    /* Send CRC or Check Sum based on CRC16_F */
                    /* Send CRC or Check Sum based on CRC16_F */
                    if (CRC16_F != 0)
                    {
                        tempCRC = Cal_CRC16(packet_data, 3, (uint)pktSize);
                        comm.Send_Byte((byte)(tempCRC >> 8));
                        comm.Send_Byte((byte)(tempCRC & 0xFF));
                    }
                    else
                    {
                        tempCheckSum = CalChecksum(packet_data, 3, (uint)pktSize);
                        comm.Send_Byte(tempCheckSum);
                    }

                    /* 延时等待Ack */
                    if ((comm.Receive_Byte(receivedC, 1000) == 0) && (receivedC[0] == (byte)YmodemCmd.ACK))
                    {
                        ackReceived = 1;
                        if (size > pktSize)
                            size -= pktSize;
                        else
                            size -= packetSize;

                        int tmp;
                        file_offset += pktSize;
                        TotalSendSize += pktSize;
                        tmp = (int)(100 * TotalSendSize / sizeFile);
                        tmp = tmp > 100 ? 100 : tmp;                

                        backgroundWorker.ReportProgress(tmp);

                        if (tmp == 100)
                        {
                            fs.Close();
                            br.Close();
                        }

                        blkNumber++;
                    }
                    else
                    {
                        errors++;
                    }

                    //如果取消下载，就停止下载；如果没有停止下载，就更新下载进度 
                    if (backgroundWorker.CancellationPending)
                    {
                        fs.Close();
                        br.Close();
                        return 1;
                    }
                } while ((0 == ackReceived) && (errors < 0x0A));
                /* Resend packet if NAK  for a count of 10 else end of commuincation */

                if (errors >= 0x0A)
                {
                    fs.Close();
                    br.Close();
                    return (byte)errors;
                }
            }
           

            /* End of session */
            ackReceived = 0;
            receivedC[0] = 0x00;
            errors = 0;
            do
            {
                comm.Send_Byte((byte)YmodemCmd.EOT);
                /* Send (EOT); */
                /* Wait for Ack */
                if ((comm.Receive_Byte(receivedC, 1000) == 0) && receivedC[0] == (byte)YmodemCmd.ACK)
                {
                    ackReceived = 1;
                }
                else
                {
                    errors++;
                }
            } while ((0 == ackReceived) && (errors < 0x0A));

            if (errors >= 0x0A)
            {
                MessageBox.Show("end of session .1. error");
                return (byte)errors;
            }

            /* Last packet preparation */
            ackReceived = 0;
            receivedC[0] = 0x00;
            errors = 0;

            packet_data[0] = (byte)YmodemCmd.SOH;
            packet_data[1] = 0;
            packet_data[2] = 0xFF;

            for (i = (uint)YmodemCmd.PACKET_HEADER; i < ((uint)YmodemCmd.PACKET_SIZE + (uint)YmodemCmd.PACKET_HEADER); i++)
            {
                packet_data[i] = 0x00;
            }

            do
            {
                // Send Packet 
                Ymodem_SendPacket(packet_data, (ushort)YmodemCmd.PACKET_SIZE + (ushort)YmodemCmd.PACKET_HEADER);
                // Send CRC or Check Sum based on CRC16_F 
                tempCRC = Cal_CRC16(packet_data, 3, (uint)YmodemCmd.PACKET_SIZE);
                comm.Send_Byte((byte)(tempCRC >> 8));
                comm.Send_Byte((byte)(tempCRC & 0xFF));


                // Wait for Ack and 'C' 
                if ((comm.Receive_Byte(receivedC, 1000) == 0)&&(receivedC[0] == (byte)YmodemCmd.ACK))
                {
                    /*
                    if ((comm.Receive_Byte(receivedC, 1000) == 0)&&(receivedC[0] == (byte)YmodemCmd.CRC16))
                    {
                        // Packet transfered correctly                        
                    }
                    */
                    ackReceived = 1;
                }
                else
                {
                    errors++;
                }
            } while ((0 == ackReceived) && (errors < 0x0A));

            // Resend packet if NAK  for a count of 10  else end of commuincation 
            if (errors >= 0x0A)
            {
                MessageBox.Show("end of session .2. error");
                return (byte)errors;
            }

            /*
            do
            {
                comm.Send_Byte((byte)YmodemCmd.EOT);
                if ((comm.Receive_Byte(receivedC, 100) == 0) && receivedC[0] == (byte)YmodemCmd.ACK)
                {
                    ackReceived = 1;
                }
                else
                {
                    errors++;
                }
            } while ((0 == ackReceived) && (errors < 0x0A));

            if (errors >= 0x0A)
            {
                return (byte)errors;
            }
             * */
            return 0; /* file trasmitted successfully */
        }

        private void DownloadFileProtocal_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (DownloadFileProtocal.Text == "Xmodem")
                config.fileprotocal = FileProtocal.Xmodem;
            else if (DownloadFileProtocal.Text == "Ymodem")
                config.fileprotocal = FileProtocal.Ymodem;
            else if (DownloadFileProtocal.Text == "Zmodem")
                config.fileprotocal = FileProtocal.Zmodem;
            else if (DownloadFileProtocal.Text == "Kermit")
                config.fileprotocal = FileProtocal.Kermit;
            else
                config.fileprotocal = FileProtocal.Xmodem;
        }
        /// <summary>
        /// 调用预置点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PresentCall_Click(object sender, EventArgs e)
        {
            
        }
        /// <summary>
        /// 设置预置点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {

        }
        /// <summary>
        /// 删除预置点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {

        }

        private void MainDialog_Load(object sender, EventArgs e)
        {
            // TODO:  这行代码将数据加载到表“userDataSet.联系人”中。您可以根据需要移动或删除它。
            this.联系人TableAdapter.Fill(this.userDataSet.联系人);

        }

        /// <summary>
        /// 用户ID选择值改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void user_id_comboBox_SelectedValueChanged(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 初始化完成数据库之后，装载用户数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void userDataSet_Initialized(object sender, EventArgs e)
        {
            string mypath = Application.StartupPath + "\\user.accdb";      //连接数据库的路径及数据库名

            string constr = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source =" + mypath;  //生成连接数据库字符串

            OleDbConnection mycon = new OleDbConnection(constr);         //定义OleDbConnection对象实例并连接数据库

            string mysql = "select * from 联系人";                //Sql查询语句

            OleDbDataAdapter myada = new OleDbDataAdapter(mysql, mycon);   //定义OleDbDataAdapter对象实例并连接数据库表

            DataSet myds = new DataSet();      //定义DataSet对象实例  
            DataTable dt = new DataTable();

            myada.Fill(myds);                 //填充数据集

            myada.Fill(myds, "infomation");

            MessageBox.Show("wait");

            mycon.Close();      //关闭OleDbConnection对象实例
            mycon.Dispose();    //释放OleDbConnection对象实例所占资源空间
        
        }



    }
}
